gsk: Fix angle normalization
authorAlexander Larsson <alexl@redhat.com>
Tue, 11 Feb 2020 09:00:34 +0000 (10:00 +0100)
committerAlexander Larsson <alexl@redhat.com>
Tue, 11 Feb 2020 12:51:06 +0000 (13:51 +0100)
I was getting assertions that normalize_angle() failed the
result < 260 check. Doing some research on this it turns out
to be a precision issue. If the incomming angle is very slightly
below zero, then adding 360 to it may end up with exactly 360.

I simplified the code a bit to avoid division and rounding, because in
practice most angles will be "just outside" the 0-360 degree anyway.
And i also added a workaround for the "result is 360" case by just
setting it to 0.

gsk/gsktransform.c

index b474ec4114cef7266d1f87f2ee657efb9553fd7b..c8e0d321b74f4bd6a679f41b3648d062da9b7e15 100644 (file)
@@ -821,20 +821,28 @@ static const GskTransformClass GSK_ROTATE_TRANSFORM_CLASS =
 static inline float
 normalize_angle (float angle)
 {
-  float f;
 
   if (angle >= 0 && angle < 360)
     return angle;
 
-  f = angle - (360 * ((int)(angle / 360.0)));
+  while (angle >= 360)
+    angle -= 360;
+  while (angle < 0)
+    angle += 360;
 
-  if (f < 0)
-    f = 360 + f;
+  /* Due to precision issues we may end up with a result that is just
+   * past the allowed range when rounded. For example, something like
+   * -epsilon + 360 when rounded to a float may end up with 360.
+   * So, we handle these cases by returning the exact value 0.
+   */
+
+  if (angle >= 360)
+    angle = 0;
 
-  g_assert (f < 360.0);
-  g_assert (f >= 0.0);
+  g_assert (angle < 360.0);
+  g_assert (angle >= 0.0);
 
-  return f;
+  return angle;
 }
 
 /**